﻿
Ext.data.Model = Ext.extend(Ext.util.Stateful, {
    evented: false,
    isModel: true,

    phantom: false, //true when the record does not yet exist in a server-side database (see setDirty). 
                    //当记录（model的实例）尚未存在于服务端的时候为true
                    //Any record which has a real database pk set as its id property is NOT a phantom(幻象) -- it's real.

    idProperty: 'id',


    /******************************************
    var user = Ext.ModelMgr.create({
        name : 'Conan',
        age  : 24,
        phone: '555-555-5555'
    }, 'User');
    ******************************************/
    constructor: function (data, id) {
        data = data || {};

        //设置id，id是全局的，另外，参数.phantom = true;
        this.internalId = (id || id === 0) ? id : Ext.data.Model.id(this);

        Ext.data.Model.superclass.constructor.apply(this);


        // 遍历属性集合
        var fields = this.fields.items,
            length = fields.length,
            field, name, i;

        for (i = 0; i < length; i++) {
            field = fields[i];
            name = field.name;

            if (data[name] == undefined) {
                data[name] = field.defaultValue; // 将模版中的默认值加入未传值的参数
            }
        }

        // 设置数据
        this.set(data);
        this.dirty = false;

        // 如果指定了id，则phantom为false（参数传进来的数据中有id值，即 data[data.idProperty]有值）
        if (this.getId()) {
            this.phantom = false;
        }

        // 如果定义了 init() 方法，则运行init方法
        if (typeof this.init == 'function') {
            this.init();
        }
    },


    validate: function () {
        var errors = new Ext.data.Errors(),
            validations = this.validations,
            validators = Ext.data.validations,
            length, validation, field, valid, type, i;

        if (validations) {
            length = validations.length;

            for (i = 0; i < length; i++) {
                validation = validations[i];
                field = validation.field || validation.name;
                type = validation.type;
                valid = validators[type](validation, this.get(field));

                if (!valid) {
                    errors.add({
                        field: field,
                        message: validation.message || validators[type + 'Message']
                    });
                }
            }
        }

        return errors;
    },

    //Returns the configured Proxy for this Model
    getProxy: function () {
        return this.constructor.proxy;
    },

    //options:配置对象，包括回调函数和作用域等
    save: function (options) {
        var me = this,
            action = me.phantom ? 'create' : 'update';//如果model中的记录还没与服务端的数据关联，则为create，否则为update
            //phantom: true when the record does not yet exist in a server-side database (see setDirty). 
            //Any record which has a real database pk set as its id property is NOT a phantom(幻象) -- it's real.

        options = options || {};

        Ext.apply(options, {
            records: [me],//记录
            action: action//动作
        });

        var operation = new Ext.data.Operation(options),
            successFn = options.success,//服务调用成功执行函数
            failureFn = options.failure,//服务调用失败执行函数
            callbackFn = options.callback, //Ext.data.BelongsToAssociation的createSetter传入的回调函数
            scope = options.scope,      //作用域
            record;

        //代理类方法的回调函数
        var callback = function (operation) {

            //Returns an array of Ext.data.Model instances as set by the Proxy.
            record = operation.getRecords()[0];

            if (operation.wasSuccessful()) {//Returns true if the Operation has completed and was successful

                //Sets the given field to the given value, marks the instance as dirty
                me.set(record.data);
                record.dirty = false; //Readonly flag - true if this Record has been modified.

                if (typeof successFn == 'function') {
                    successFn.call(scope, record, operation);//执行服务调用成功返回函数
                }
            } else {
                if (typeof failureFn == 'function') {
                    failureFn.call(scope, record, operation);//执行服务调用失败返回函数
                }
            }

            if (typeof callbackFn == 'function') {
                callbackFn.call(scope, record, operation); //执行Ext.data.BelongsToAssociation的createSetter传入的回调函数
            }
        };

        me.getProxy()[action](operation, callback, me);//调用内置代理类的方法

        return me;
    },


    getId: function () {
        return this.get(this.idProperty);
    },


    setId: function (id) {
        this.set(this.idProperty, id);
    },

    //告诉这个model的实例，它已被添加到store中
    join: function (store) {

        this.store = store;
    },

    //告诉这个model实例，它已经从store中移除
    unjoin: function (store) {
        delete this.store;
    },

    //编辑结束的操作
    afterEdit: function () {
        this.callStore('afterEdit'); //调用store的afterEdit方法
    },


    afterReject: function () {
        this.callStore("afterReject");
    },


    afterCommit: function () {
        this.callStore('afterCommit');
    },

    //调用store的fn方法
    callStore: function (fn) {
        var store = this.store;

        if (store != undefined && typeof store[fn] == "function") {
            store[fn](this);
        }
    }
});

Ext.apply(Ext.data.Model, {//用apply给Model添加类方法

    //为当前模型设置代理， 接受一切Ext.data.ProxyMgr.create能接受的参数
    setProxy: function (proxy) {

        //创建代理类实例
        proxy = Ext.data.ProxyMgr.create(proxy);

        proxy.setModel(this); //this就是Model，（Ext.ModelMgr的Ext.data.Model.setProxy.call(model, proxy || this.defaultProxyType);跳转到这个方法中）
        this.proxy = proxy;

        return proxy;
    },


    load: function (id, config) {
        config = Ext.applyIf(config || {}, {
            action: 'read',
            id: id
        });

        var operation = new Ext.data.Operation(config),
            callbackFn = config.callback,
            successFn = config.success,
            failureFn = config.failure,
            scope = config.scope,
            record, callback;

        callback = function (operation) {
            record = operation.getRecords()[0];

            if (operation.wasSuccessful()) {
                if (typeof successFn == 'function') {
                    successFn.call(scope, record, operation);
                }
            } else {
                if (typeof failureFn == 'function') {
                    failureFn.call(scope, record, operation);
                }
            }

            if (typeof callbackFn == 'function') {
                callbackFn.call(scope, record, operation);
            }
        };

        this.proxy.read(operation, callback, this);
    }
});


Ext.data.Model.id = function (rec) {
    rec.phantom = true;
    return [Ext.data.Model.PREFIX, '-', Ext.data.Model.AUTO_ID++].join('');
};

Ext.data.Model.PREFIX = 'ext-record';
Ext.data.Model.AUTO_ID = 1;
Ext.data.Model.EDIT = 'edit';
Ext.data.Model.REJECT = 'reject';
Ext.data.Model.COMMIT = 'commit';